<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>watch-侦听器</title>
    <!--<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.0-beta.7/vue.global.js"></script>-->
    <script type="text/javascript" src="../../js/vue.global.js"></script>

</head>
<body>
<!--vue 应用实例挂载到此ID上，这样它及其下面的标签才能使用 vue 语法获取数据-->
<div id="rootApp" style="margin: 50px">
    <h3>watch-侦听器</h3>
    <p>watch 选项在每次响应式属性发生变化时触发一个函数。</p>
    <p>watch 默认是浅层的：被侦听的属性，仅在被赋新值时，才会触发回调函数——而嵌套属性的变化不会触发。<br/>
        如果想侦听所有嵌套的变更，需要深层侦听器：deep: true</p>
    <p>深度侦听需要遍历被侦听对象中的所有嵌套的属性，当用于大型数据结构时，开销很大。因此请只在必要时才使用它，并且要留意性能。</p>
    <p>watch 默认是懒执行的：仅当数据源变化时，才会执行回调，如果希望在创建侦听器时，立即执行一遍回调，则可以添加：immediate: true 选项</p>


    家庭住址：<input type="text" v-model.trim="home_address" placeholder="edit me"/><br/>
    姓名：<input type="text" v-model.trim="students[0].name" placeholder="edit me"/><br/>
    年龄：<input type="number" v-model.trim="students[0].age" placeholder="edit me"/><br/>

</div>
</body>

<script type="text/javascript">
    const author = "蚩尤后裔";
    const students = [{"name": "张三", "age": "15"}, {"name": "李四", "age": "17"}, {"name": "王五", "age": "16"}];

    // 1、每个 Vue 应用都是通过用 createApp 函数创建一个新的应用实例开始, 用来在应用中注册"全局"组件
    // 2、传递给 createApp 的选项用于配置根组件
    // 3、应用实例暴露的大多数方法都会返回该同一实例，方便链式编程
    const App = Vue.createApp({
        // 组件选项
        // data 定义数据, html 中可以进行获取
        data() {
            return {
                author,
                home_address: "长沙",
                students
            }
        },
        watch: {
            // 监控普通类型(函数名称与监控的变量或对象名称一致)
            // 每当 home_address 的值改变时，这个函数就会执行。
            home_address(oldValue, newValue) {
                console.log(oldValue + '->' + newValue);
            },
            // 监控复杂对象(函数名称与监控的变量或对象名称一致)
            students: {
                // 必须开启深度监控，才能监控对象中属性值的变化。
                deep: true,
                // 创建侦听器时，强制立即执行回调
                immediate: true,
                // 默认情况下，用户创建的侦听器回调，都会在 Vue 组件更新之前被调用。
                // 如果想在侦听器回调中能访问被 Vue 更新之后的 DOM，需要指明 flush: 'post' 选项
                flush: 'post',
                // 获取到最新的整个对象值
                handler(oldObj, newObj) {
                    if (!newObj) {
                        console.log("初始化请求数据！");
                        return;
                    }
                    // 注意：在嵌套的变更中，只要没有替换对象本身，那么这里的 oldObj 和 newObj 相同
                    console.log(JSON.stringify(newObj));
                }
            }
        }
    });

    // 4、一个应用需要被挂载(mount)到一个 DOM 元素中，当挂载(mount)应用时，该组件被用作渲染的起点
    // 5、与大多数应用方法不同的是 mount 不返回应用本身，而是返回的根组件实例(vm)
    const rootViewModel = App.mount("#rootApp");
    console.log(rootViewModel.author);

</script>
</html>
